classdef CMerge< handle & matlab.mixin.Copyable
    properties
        imageHeight;
        imageWidth;
        imagePath;
        img;
        quality = 10;
        wsize = 800;
        tol = 50;
        boxes;
        overlaps;
        fixlap = 150;
        columns = 0; %图片分割时按行优先进行分割
        nums = 0;%%分割图像个数
        patchs;
    end
    methods
        function obj = CMerge(columns, nums) %返回值必须是一个obj
            obj.nums = nums;
            obj.columns = columns;
        end
        
        % % 获取检测结果文件，分子图片
        function patchs = getFiles(obj, imgName, dir_dectect_res, dir_ground_truth, iou, ratio)
            cols = obj.columns;
            nums = obj.nums;
            rows = nums / cols;
            
            % %             patchs = cell(rows, cols);
            patchs(rows, cols)= CPatch();
            
            for j = 1 : nums
                row = floor((j - 1)/ cols) + 1;
                col = mod(j - 1, cols) + 1;
                strSub = CImage.getString(j, cols);
                
                fileGroundTrue = fullfile(dir_ground_truth, ...
                    sprintf('%s_%s.txt', imgName, strSub));
                
                fileDetectRes = fullfile(dir_dectect_res, ...
                    sprintf('%s_%s.txt', imgName, strSub));
                
                patchs(row, col) = CPatch(fileGroundTrue, fileDetectRes, iou);
                
% %                 patchs(row, col).supressPartials(ratio);%%抑制高分partial
                patchs(row, col).findEdgeBox();%%查找边缘元素
                patchs(row, col).supressEdges(ratio);%%查找边缘元素
            end
            obj.patchs = patchs;
        end
        
        %% detects = [label, score, xmin, ymin, xmax, ymax, isEdge, score_orgin], 0-based
        function detects = getMatchPatches(obj, boxes)
            patchs = obj.patchs;
            
            detects = [];
            
            cols = obj.columns;
            nums = obj.nums;
            rows = nums / cols;
            
            for j = 1 : nums
                row = floor((j - 1)/ cols) + 1;
                col = mod(j - 1, cols) + 1;
                box = boxes(j, :);
                left = box(1);
                top  = box(2);
                
                patch = patchs(row, col);
                offDet = patch.detects;
                
                if isempty(offDet)
                    continue;
                end
                offDet(:, 3) = offDet(:, 3) + left;
                offDet(:, 4) = offDet(:, 4) + top;
                offDet(:, 5) = offDet(:, 5) + left;
                offDet(:, 6) = offDet(:, 6) + top;
                
                detects = [detects; offDet];
            end
            return
            ins = detects(:, 1) == 2;
            partials = detects(ins, :);
            seeds = detects(~ins, :);
            
        end
    end
    
    methods(Static = true)
        %% NMS 抑制相邻框
        function [sBbox,sScore,ins, detects] = NMSboxes(detects, thresh)
            boxes = detects(:, 3:6);
            boxes(:, 3) = boxes(:, 3) - boxes(:, 1);
            boxes(:, 4) = boxes(:, 4) - boxes(:, 2);
            
            score = detects(:, 2);
            [sBbox,sScore, ins] = selectStrongestBbox(boxes, score, ...
                                           'OverlapThreshold', thresh);
            % % 这里要根据不同类别进行NMS
            sset = 1 : size(detects, 1);
            sset = setdiff(sset', ins);
            detects(sset, 1) = detects(sset, 1) + 128;            
        end
        
        %% 去除边缘元素与seed重叠的box
        function detects = RefineBoxes(detects)
            ins2 = find(detects(:, 1) == 2 | detects(:, 7) == 1);%%7=1是边缘
            ins1 = find(detects(:, 1) < 2 & detects(:, 7) == 0);%%7=0是非边缘            
            
           %% Step 1:把重叠在seed的partial/边缘元素去除
            for i = 1 : length(ins2)
                id = ins2(i);
                part = detects(id, :);
                for j = 1 : length(ins1)
                    ii = ins1(j);
                    seed = detects(ii, :);
                    
                    [isBelong, merge] =  CMerge.isMostBelongto(part, seed, 0.5);
                        
                    if isBelong == true
                        detects(id, 1) = detects(id, 1) + 256;
% % %                         disp([id, part]);
                        continue;
                    end
                end
            end    
            
            %% Step 2: 把重叠的seed 去除
            for i = 1 : length(ins1)
                id   = ins1(i);
                seedL = detects(id, :);
                for j = 1 : length(ins1)
                    if j == i
                        continue;
                    end
                    if detects(id, 1) >= 256
                        continue;
                    end
                    
                    ii   = ins1(j);
                    seed = detects(ii, :);
                    
                    [isBelong, merge] =  CMerge.isMostBelongto2(seedL, seed, 0.75, 0.15);
                        
                    if isBelong == true
                        detects(id, 1)   = detects(id, 1) + 256;
%                         detects(ii, 3:6) = merge;  
                        disp([-id, seedL]);%%与上面的处理做区别
                        
                        continue;
                    end
                end
            end 
        end
        
        %% 判断partial或边界元素是否落在seed部分
        function [isBelong, merge] = isMostBelongto(setPart, setBig, thresh)           
            isBelong = false;
            merge = [];
            
            [isInside, areaLap] = CMerge.isInsideBig(setPart, setBig);
            if isInside == false
                return;
            end
            
            areaPart = (setPart(6) - setPart(4)) * (setPart(5) - setPart(3));
            areaBig  = (setBig(6) - setBig(4)) * (setBig(5) - setBig(3));
            
            thresh1 = thresh * 0.9;%%针对partial
            thresh2 = thresh;%%针对边界元素
            
            label = setPart(1);
            if areaLap / areaPart < thresh1 && bitand(label, 2)==true
                return;
            elseif areaLap / areaPart < thresh2 && bitand(label, 2)==false
                return;
            end
            isBelong = true;
            
            merge = CMerge.CalcMerge(setPart, setBig);
        end
        
        %% 增加
        function [isBelong, merge] = isMostBelongto2(setPart, setBig, thresh1, thresh2)
            isBelong = false;
            merge = [];
            
            [isInside, areaLap] = CMerge.isInsideBig(setPart, setBig);
            if isInside == false
                return;
            end

            areaPart = (setPart(6) - setPart(4)) * (setPart(5) - setPart(3));
            areaBig  = (setBig(6) - setBig(4)) * (setBig(5) - setBig(3));            

            if areaLap / areaPart < thresh1
                return;
            end
            if (areaPart - areaLap) / areaBig > thresh2
                return;
            end
            
            isBelong = true;
            
            merge = CMerge.CalcMerge(setPart, setBig);
        end

        %%检查是否part 在 big里面
        function [isBelongto, areaLap] = isInsideBig(setPart, setBig)
            leftMax   = max(setPart(3), setBig(3));
            topMax    = max(setPart(4), setBig(4));
            rightMin  = min(setPart(5), setBig(5));
            bottomMin = min(setPart(6), setBig(6));
            
            areaLap  = (bottomMin - topMax) * (rightMin - leftMax);
            if bottomMin < topMax || rightMin < leftMax                
                isBelongto = false;
            else
                isBelongto = true;
            end
        end
        %% 计算合并区域
        function merge = CalcMerge(setPart, setBig)
            leftMin    = min(setPart(3), setBig(3));
            topMin     = min(setPart(4), setBig(4));
            rightMax   = max(setPart(5), setBig(5));
            bottomMax  = max(setPart(6), setBig(6));
            
            merge = [leftMin, topMin, rightMax, bottomMax];
        end
                
       %% 统计种子区域
       function data = StatSeeds(detects)
          seeds   = sum(detects(:, 1) == 0);
          seed_1  = sum(detects(:, 1) == 1);
          partial = sum(detects(:, 1) == 2);
          data = [seeds, seed_1, partial, seeds+seed_1];
       end  
       % % % % % % % % % % % % % %
       % % % % % % % % % % % % % % % % % %
       % % 在图片矩阵中绘制 box
        function SaveImageAndBoxes(img, fileSaveDrawBox, detects, isDraw128)
            for i = 1 : size(detects,1)
                label = detects(i, 1);
                
                box = detects(i, 3:6) + 1;
                
                if label == 0
                    img = Helper.Drawrectangle(img, [box(1), box(3)], [box(2), box(4)], [0, 0, 255]);
                elseif label == 1
                    img = Helper.Drawrectangle(img, [box(1), box(3)], [box(2), box(4)], [255, 0, 0]);
                elseif label == 2
                    img = Helper.Drawrectangle(img, [box(1), box(3)], [box(2), box(4)], [0, 0, 0]);
                elseif label >= 128 
                    if isDraw128 == false
                        continue;
                    end
                    label2 = label - 128;
                    if label2 == 0
                        img = Helper.Drawrectangle(img, [box(1), box(3)], [box(2), box(4)], [128, 128, 0]);
                    elseif label2 == 1
                        img = Helper.Drawrectangle(img, [box(1), box(3)], [box(2), box(4)], [128, 0, 128]);
                    elseif label2 == 2
                        img = Helper.Drawrectangle(img, [box(1), box(3)], [box(2), box(4)], [0, 128, 128]);
                    end
                else
                    disp('error....')
                end
            end
            imwrite(img, fileSaveDrawBox, 'Quality', 85);
            
        end
        %%画出矩形框
        function drawBoxes(detects, isDraw128)
            hold on
            
            for i = 1 : size(detects,1)
                label = detects(i, 1);
                points = detects(i, 3:6);
                
                box = [points(1) + 1, points(2) + 1, ...
                    points(3) - points(1), points(4) - points(2)];
                
                if label == 0
                    rectangle('Position', box, 'EdgeColor','b')
                elseif label == 1
                    rectangle('Position', box, 'EdgeColor','r')
                elseif label == 2
                    rectangle('Position', box, 'EdgeColor','k')
                elseif label >= 128 
                    if isDraw128 == false
                        continue;
                    end
                    label2 = label - 128;
                    if label2 == 0
                        rectangle('Position', box, 'EdgeColor', [0.5, 0.5, 0.0])
                    elseif label2 == 1
                        rectangle('Position', box, 'EdgeColor', [0.5, 0.0, 0.5])
                    elseif label2 == 2
                        rectangle('Position', box, 'EdgeColor', [0.0, 0.5, 0.5])
                    end                    
                else
                    disp('error')
                end
            end
            hold off
        end
        
    end
end



